package cmap

import (
	"github.com/pkg/errors"
	"sync/atomic"
)

type Bucket interface {
	Get(key string) Item
	GetFirstItem() Item
	Set(item Item)(bool,error)
	Clear()
	Delete(key string) bool
	Size()uint64
}
type myBucket struct {
	firstItem atomic.Value
	size uint64
}
var oneItem = &myItem{}
func (this *myBucket)GetFirstItem() Item  {
	firstItem := this.firstItem.Load()
	//fmt.Println(firstItem)
	if firstItem == nil{
		return nil
	}else if it,ok :=firstItem.(Item);!ok||it==oneItem{
		return nil
	}else{
		return it
	}
}
func (this *myBucket)Get(key string)Item  {
	first := this.GetFirstItem()
	if first == nil{
		return nil
	}
	for v := first;v !=nil;v = v.Next(){
		if v.Key()== key{
			return v
		}
	}
	return nil
}
func (this *myBucket)Set(item Item)(bool,error)  {
	if item==nil{
		return false,errors.New("item is nil")
	}
	first := this.GetFirstItem()
	if first == nil{
		this.firstItem.Store(item)
		atomic.AddUint64(&this.size,1)
		return true,nil
	}
	var target Item
	for v := first;v != nil;v = v.Next(){
		if v.Key() == item.Key(){
			target = v
		}
	}
	if target != nil{
		target.SetValue(item.Value())
		return false,nil
	}
	item.SetNext(first)
	this.firstItem.Store(item)
	atomic.AddUint64(&this.size,1)
	return true,nil
}
func (this *myBucket)Clear(){
	this.firstItem.Store(oneItem)
}
func (this *myBucket)Delete(key string) bool {
	first := this.GetFirstItem()
	if first == nil{
		return false
	}
	var prevItems []Item
	var target Item
	for v := first;v != nil;v = v.Next(){
		if v.Key() == key{
			target = v
			break
		}
		prevItems = append(prevItems,v)
	}
	if target == nil{
		return false
	}
	newFirst := target.Next()

	for len := len(prevItems)-1;len>=0;len--{
		p := prevItems[len].Copy()
		p.SetNext(newFirst)
		newFirst = p
	}
	if newFirst ==nil{
		this.firstItem.Store(oneItem)
	}else{
		this.firstItem.Store(newFirst)
	}
	//fmt.Println(1)
	atomic.AddUint64(&this.size,^uint64(0))
	return true
}
func (this *myBucket) Size()uint64 {
	return atomic.LoadUint64(&this.size)
}
func NewBucket()Bucket {
	bucket := &myBucket{}
	bucket.firstItem.Store(oneItem)
	return bucket
}